package com.example.opengldemo.vertex_magical.shader;

import android.content.res.Resources;
import android.opengl.GLES30;

import com.example.opengldemo._camera_demo.buffer.FrameBuffer;
import com.example.opengldemo.util.MatrixUtils;
import com.example.opengldemo.util.ShaderBuffer;
import com.example.opengldemo.util.ShaderHandle;
import com.example.opengldemo.util.ShaderUtil;
import com.example.opengldemo.vertex_magical.core.FrameRenderer;

import java.util.LinkedList;

public class BaseRenderer implements FrameRenderer {

    protected float[] mVertexMatrix= MatrixUtils.getOriginalMatrix();
    protected float[] mTextureMatrix=MatrixUtils.getOriginalMatrix();

    protected int mWidth;
    protected int mHeight;

    protected Resources mRes;
    private String mVertex;
    private String mFragment;


    protected ShaderHandle shaderHandle ;
    protected ShaderBuffer shaderBuffer ;

    private FrameBuffer mFrameTemp;

    private final LinkedList<Runnable> mTasks=new LinkedList<>();
    private final Object Lock = new Object();

    protected BaseRenderer(Resources resource, String vertex, String fragment){
        this.mRes=resource;
        this.mVertex=vertex;
        this.mFragment=fragment;
        mFrameTemp=new FrameBuffer();
        initBuffer();
    }

    protected void initBuffer(){
        shaderBuffer = new ShaderBuffer() ;
        shaderBuffer.setVertexBuffer(MatrixUtils.get3OriginalVertexCo());
        shaderBuffer.setTexcoorBuffer(MatrixUtils.getOriginalTextureCo());
    }


    protected void onCreate(){
        if(mRes !=null ){
            shaderHandle = new ShaderHandle(ShaderUtil.createProgram(ShaderUtil.loadFromAssetsFile(mVertex , mRes) , ShaderUtil.loadFromAssetsFile(mFragment , mRes))) ;
        }else{
            shaderHandle = new ShaderHandle(ShaderUtil.createProgram(mVertex,mFragment)) ;
        }
    }

    protected void onSizeChanged(int width,int height){

    }

    public void setVertexCo(float[] vertexCo){
        shaderBuffer.setVertexBuffer(vertexCo);
    }

    public void setTexCoors(float[] texCoors){
        shaderBuffer.setTexcoorBuffer(texCoors);
    }
    public float[] getVertexMatrix(){ return mVertexMatrix; }

    public float[] getTextureMatrix(){
        return mTextureMatrix;
    }
    @Override
    public void create() {
        if(mVertex!=null&&mFragment!=null){
            onCreate();
        }
    }
    @Override
    public void sizeChanged(int width, int height) {
        this.mWidth=width;
        this.mHeight=height;
        onSizeChanged(width, height);
        mFrameTemp.destroyFrameBuffer();
    }

    @Override
    public void draw(int texture) {
        onClear();
        onUseProgram();
        onSetExpandData();
        onBindTexture(texture);
        onDraw();
        onDrawEnd() ;
    }

    protected void onDrawEnd() {

    }

    public int drawToTexture(int texture){
        mFrameTemp.bindFrameBuffer(mWidth,mHeight);
        draw(texture);
        mFrameTemp.unBindFrameBuffer();
        return mFrameTemp.getCacheTextureId();
    }

    @Override
    public void destroy() {
        mFrameTemp.destroyFrameBuffer();
        if(shaderHandle != null)
            shaderHandle.destroy();
    }

    protected void onTaskExec(){
        synchronized (Lock) {
            while (!mTasks.isEmpty()){
                mTasks.removeFirst().run();
            }
        }
    }

    protected void onUseProgram(){
        shaderHandle.program() ;
        onTaskExec();
    }

    protected void onDraw(){
        shaderHandle.bindTexCoorsHandle(shaderBuffer.getTexcoorBuffer()) ;
        shaderHandle.bindVertexHandle(shaderBuffer.getVertexBuffer()) ;
        shaderHandle.run(GLES30.GL_TRIANGLE_STRIP,shaderBuffer.vCount);
    }

    protected void onClear(){
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
    }

    public void runOnGLThread(Runnable runnable){
        synchronized (Lock) {
            mTasks.addLast(runnable);
        }
    }

    /**
     * 设置其他扩展数据
     */
    protected void onSetExpandData(){
        shaderHandle.bindMVPMaxtrixHandle(mVertexMatrix) ;
        shaderHandle.bindTMaxtrixHandle(mTextureMatrix) ;
    }

    /**
     * 绑定默认纹理
     */
    protected void onBindTexture(int textureId){
        shaderHandle.bindDefaultTextureHandle(textureId) ;
    }
}
